//本脚本记录所有教学步骤对象

import EventManager, { Handler } from "../../Script/Common/EventManager";
import { EventType } from "../../Script/GameSpecial/GameEventType";
import { GlobalEnum } from "../../Script/GameSpecial/GlobalEnum";
import Loader from "../../Script/Common/Loader";
import { Node, instantiate, director, Prefab, v3 } from "cc";
import yyComponent from "../../Script/Common/yyComponent";
import GlobalData from "../../Script/Common/GlobalData";
import { RoleNameCfg } from "../../Script/GameSpecial/RoleNameCfg";

/**管理所有教学步骤对象 */
export default class TeachStepData {

    protected static stepQuence = [];
    /**添加教学步骤(将按顺序添加在最后) */
    public static push(step: TeachStep) {
        if (this.stepQuence.indexOf(step) < 0) {
            this.stepQuence.push(step);
        }
    }
    /**获取教学步骤数据 */
    public static getTeachData() {
        let data = [];
        for (let i = 0, c = this.stepQuence.length; i < c; ++i) {
            let cor = this.stepQuence[i];
            let step = new cor();
            step.init();
            data.push(step);
        }
        return data;
    }
    /**创建教学关卡数据 */
    public static createTeachLevelData() {
        createTeachLevelData();
    }
}

/**添加教学步骤(将按顺序添加在最后) */
function regist(step) {
    TeachStepData.push(step);
}

/**教学步骤所处状态 */
export enum TeachState {

    /**已初始化完成 */
    inited,
    /**正在教学 */
    teaching,
    /**玩家已成功执行(该步骤已教学完成) */
    success,
    /**玩家操作失败 */
    fail,
}

/**教学步骤基类 */
class TeachStep {
    /************************************************************事件管理器************************************************************/
    //#region 事件注册
    /**
     * 记录所有事件类型与对应回调函数的字典，销毁脚本时，根据此字典注销其事件
     * key:事件类型枚举值
     * value:事件类型对应的回调函数数组
     */
    private events: { [type: number]: Handler[] } = {};
    /**
     * 记录所有只触发一次的事件类型与对应回调函数的字典
     * key:事件类型枚举值
     * value:事件类型对应的回调函数数组
     */
    private onceEvents: { [type: number]: Handler[] } = {};
    /**
     * 注册事件
     * @param {number} type 事件类型枚举值
     * @param {Function} cb 回调函数
     * @param {Object} target 函数所属对象
     */
    public on(type: number, cb: Function, target: Object) {
        let h: Handler = EventManager.on(type, cb, target);
        if (!!h) {
            if (!this.events.hasOwnProperty(type)) {
                this.events[type] = [];
            }
            this.events[type].push(h);
        }
    }
    /**
     * 注册只触发一次的事件
     * @param {number} type 事件类型枚举值
     * @param {Function} cb 回调函数
     * @param {Object} target 函数所属对象
     */
    public once(type: number, cb: Function, target: Object) {
        let h: Handler = EventManager.once(type, cb, target);
        if (!!h) {
            if (!this.onceEvents.hasOwnProperty(type)) {
                this.onceEvents[type] = [];
            }
            this.onceEvents[type].push(h);
        }
    }
    //#endregion

    //#region 事件发射
    /**
     * 发送事件
     * @param {number} type 事件类型枚举值
     * @param {any} data 传给回调函数的参数
     */
    public emit(type: number, d1?: any, d2?: any) {
        if (undefined === d1) {
            EventManager.emit(type);
        } else if (undefined === d2) {
            EventManager.emit(type, d1);
        } else {
            EventManager.emit(type, d1, d2);
        }
        if (this.onceEvents.hasOwnProperty(type)) delete this.onceEvents[type];
    }
    //#endregion

    //#region 事件注销
    public off(type: number, cb: Function, target: Object) {
        let events = this.events[type];
        if (!!events) {
            for (let i = events.length - 1; i >= 0; --i) {
                if (events[i].cb === cb && events[i].target === target) {
                    EventManager.off(type, events[i]);
                    events.splice(i, 1);
                }
            }
        }
        events = this.onceEvents[type];
        if (!!events) {
            for (let i = events.length - 1; i >= 0; --i) {
                if (events[i].cb === cb && events[i].target === target) {
                    EventManager.off(type, events[i]);
                    events.splice(i, 1);
                }
            }
        }
    }
    /**
     * 注销脚本中注册的所有事件
     */
    public offEvents() {
        for (let key in this.events) {
            EventManager.offGroup(key, this.events[key]);
        }
        this.events = {};
        for (let key in this.onceEvents) {
            EventManager.offGroup(key, this.onceEvents[key]);
        }
        this.onceEvents = {};
    }
    //#endregion

    public id: number = 0;
    protected state: TeachState;
    public init() { }
    public reset() { }
    public destroy() { }
    public enter() { }
    public exit() { }
    public enterNext() {
        this.emit(EventType.Common.TeachEvents.enterNextTeach);
    }

    protected success() {
        this.emit(EventType.Common.UIEvent.showTouchMask);
        setTimeout(() => {
            this.enterNext();
            this.emit(EventType.Common.UIEvent.hideTouchMask);
        }, 1500);
    }
    protected fail() {
        this.restart();
    }
    protected restart() { }
}

/************************************************************具体的教学步骤************************************************************/
/**创建教学关卡数据 */
function createTeachLevelData() {
    let arr = [];
    let ids = [];
    //todo:读取角色名字文件，随机选取count个
    for (let i = 0; i < 5; ++i) {
        arr.push(RoleNameCfg.getRandomName(ids));
    }
    GlobalData.set(GlobalEnum.myGlobalDataType.matchEnemyNames, arr);
    let data = [];
    for (let i = 0; i < 5; ++i) {
        let enemy = randomMatchEnemyData();
        data.push(enemy);
    }
    data[0].p = v3(5, 0, 5);
    data[1].p = v3(2, 0, -1.5);
    data[2].p = v3(-27, 0, -36);
    data[3].p = v3(-19, 0, -42);
    data[4].p = v3(-47, 0, 0);
    GlobalData.set(GlobalEnum.myGlobalDataType.matchEnemies, data);
    GlobalData.set(GlobalEnum.myGlobalDataType.matchMap, [2, 5, 4, 8]);
}
function randomMatchEnemyData() {
    let data: any = {
        weaponType: GlobalEnum.WeaponType.captain,
        weaponId: 1,
        skin: 6,
        hat: 0,
        invicible: 0,
    };
    return data;
}

//准备教学资源
class stepReady extends TeachStep {
    public id: number = 0;
    protected arrow: Node = null;
    protected ui: Node = null;
    public enter() {
        Loader.loadBundleRes("Teach", "Prefab/TeachArrow", (res) => {
            let node = instantiate(res);
            this.arrow = node;
            let js = node.getComponent(yyComponent);
            js.init();
            director.getRunningScene().getChildByName("LevelManager").addChild(node);
            node.active = false;
            Loader.loadBundleRes("Teach", "Prefab/TeachAnim", (res) => {
                let ui = instantiate(res);
                this.ui = ui;
                let anim = ui.getComponent(yyComponent);
                anim.init();
                director.getRunningScene().getChildByName("Canvas").getChildByName("UI").getChildByName("TeachAnim").addChild(ui);
                anim.show();
                this.enterNext();
            }, Prefab, true);
        }, Prefab, true);
    }
    public destroy() {
        this.arrow.destroy();
        this.ui.destroy();
    }

}
regist(stepReady);

class step1 extends TeachStep {
    public id: number = 1;
    protected state: TeachState;
    protected weaponType = GlobalEnum.WeaponType.katana;
    protected weaponId = 1;
    public enter() {
        this.emit(EventType.Common.PlayerDataEvent.updatePlayerData, {
            attribute: "gameData.WeaponSkin.try",
            value: {
                type: this.weaponType,
                id: this.weaponId,
            },
            mode: "=",
            emit: false,
            save: false,
        });
        this.emit(EventType.LevelEvent.changePlayerSkin);
        this.once(EventType.myTeachEvent.decideTip, this.onDecideTip, this);
        this.emit(EventType.myTeachEvent.showTeachTip, {
            weaponImg: "weapon1",
            str: "近战武器的攻击角度最大，\n使用它去攻击前面的敌人吧",
        });
    }
    protected onDecideTip() {
        let enemies = GlobalData.get(GlobalEnum.myGlobalDataType.enemies);
        let node = enemies[0].node;
        let pos = node.position;
        this.emit(EventType.myTeachEvent.setArrowTargetPos, pos);
        this.once(EventType.LevelEvent.enemyDead, this.success, this);
    }
}
regist(step1);

class step2 extends TeachStep {
    protected weaponType = GlobalEnum.WeaponType.gun;
    protected weaponId = 1;
    public enter() {
        this.emit(EventType.Common.PlayerDataEvent.updatePlayerData, {
            attribute: "gameData.WeaponSkin.try",
            value: {
                type: this.weaponType,
                id: this.weaponId,
            },
            mode: "=",
            emit: false,
            save: false,
        });
        this.emit(EventType.LevelEvent.changePlayerSkin);
        this.once(EventType.myTeachEvent.decideTip, this.onDecideTip, this);
        this.emit(EventType.myTeachEvent.showTeachTip, {
            weaponImg: "weapon2",
            str: "远程武器的攻击距离最远，\n试试用它击中前面的敌人",
        });
    }
    protected onDecideTip() {
        let enemies = GlobalData.get(GlobalEnum.myGlobalDataType.enemies);
        let node = enemies[0].node;
        let pos = node.position;
        this.emit(EventType.myTeachEvent.setArrowTargetPos, pos);
        this.once(EventType.LevelEvent.enemyDead, this.success, this);
    }
}
regist(step2);

class step3 extends TeachStep {
    public enter() {
        this.once(EventType.myTeachEvent.decideTip, this.onDecideTip, this);
        this.emit(EventType.myTeachEvent.addPortals);
        this.emit(EventType.myTeachEvent.showTeachTip, {
            showPortal: true,
            str: "通过传送门可以进入其他区域，\n快传送过去吧",
        });
    }
    protected onDecideTip() {
        let portals = GlobalData.get(GlobalEnum.myGlobalDataType.portals);
        let node = portals[portals.length - 2].node;
        let pos = node.position;
        this.emit(EventType.myTeachEvent.setArrowTargetPos, pos);
        this.once(EventType.LevelEvent.enemyDead, this.success, this);
    }
}
regist(step3);

class step4 extends TeachStep {
    protected weaponType = GlobalEnum.WeaponType.trapper;
    protected weaponId = 1;
    public enter() {
        this.emit(EventType.Common.PlayerDataEvent.updatePlayerData, {
            attribute: "gameData.WeaponSkin.try",
            value: {
                type: this.weaponType,
                id: this.weaponId,
            },
            mode: "=",
            emit: false,
            save: false,
        });
        this.emit(EventType.LevelEvent.changePlayerSkin);
        this.once(EventType.myTeachEvent.decideTip, this.onDecideTip, this);
        this.emit(EventType.myTeachEvent.showTeachTip, {
            weaponImg: "weapon3",
            str: "炸弹扔出后可长时间存在，\n快试试它的威力吧",
        });
    }
    protected onDecideTip() {
        let enemies = GlobalData.get(GlobalEnum.myGlobalDataType.enemies);
        let node = enemies[0].node;
        let pos = node.position;
        this.emit(EventType.myTeachEvent.setArrowTargetPos, pos);
        this.once(EventType.LevelEvent.enemyDead, this.success, this);
    }
}
regist(step4);

class stepFinish extends TeachStep {
    public enter() {
        this.once(EventType.myTeachEvent.gotTeachAward, this.onGotTeachAward, this);
        this.emit(EventType.myTeachEvent.showTeachAward);
    }
    protected onGotTeachAward() {
        this.emit(EventType.Common.PlayerDataEvent.trySkinEnd);
        this.emit(EventType.Common.TeachEvents.enterNextTeach);
    }
}
regist(stepFinish);
